# encoding = utf-8

import pandas as pd

from application.data_process.calc_weighted_temper import func_calc_weighted_temper
from application.data_process.data_process_accum.Temperature_Missing_value_database import \
    Temperature_Missing_value_database
from application.data_process.data_process_accum.process_data_each_day_calculate import \
    process_data_each_day_calculate
from application.data_process.get_area_code import func_get_area_code
from application.data_process.read_inside_temperature_data import \
    func_read_inside_temperature_data
from application.data_process.read_station_data import func_read_station_data
from application.data_process.read_station_id_model_name import read_station_id_model_name
from application.logging import logger
from application.utils.CodeTimingUtil import CodeTimingUtil
from application.utils.DatabasePrimaryKeyGeneratorUtil import DatabasePrimaryKeyGeneratorUtil
from application.utils.MySQLUtils import MySQLUtils


@CodeTimingUtil(name="累热模型数据处理[func_main_data_process_accum]")
def func_main_data_process_accum():
    """
    数据预处理:累热
    :return:
    """
    #
    # 读取数据
    station_id_name: pd.DataFrame = read_station_id_model_name()
    logger.info(f"热力站模型表数据:\n {station_id_name}")

    #
    # 热力站ID列表
    station_id_list = list(station_id_name["station_id"])
    logger.info(f"热力站编号列表[station_id_list]: {station_id_list}")

    #
    # 数据循环:模型列表
    # for ->
    for j_name, station_id in enumerate(station_id_list):
        logger.info(f"热力站编号[station_id]: {station_id}")
        #
        # 查询数据:热力站历史工况数据
        station_data = func_read_station_data(station_id=station_id, data_type="accum")
        # TODO 打印开始和结束时间（作为对比）
        logger.info(f"[未处理的]热力站历史工况数据[{station_id}]:\n {station_data}")
        logger.info(f"[未处理的]热力站历史工况数据[{station_id}][len]: {len(station_data)}")

        # --------------------------------------------------------------------------------------------------------------
        # 热力站历史工况数据为空:否
        # --------------------------------------------------------------------------------------------------------------
        # if ->
        if (station_data is not None) and (not station_data.empty):
            # 更新语句: status_accum=1 : 0-未处理, 1-正在处理, 2-已处理
            sql = f"UPDATE sn_control_model_station SET status_accum=1 WHERE status_accum=0"
            con = MySQLUtils.get_mysql_connection()
            # 获取游标
            cur = con.cursor()
            cur.execute(sql)
            # 提交事务
            con.commit()
            # 关闭连接
            cur.close()
            con.close()

            #
            model_name = list(station_id_name["model_name"])[j_name]

            #
            # 数据处理
            day_heat_main_data_process(station_id=station_id, station_data=station_data, model_name=model_name)
            pass  # if <-
        # --------------------------------------------------------------------------------------------------------------
        # 热力站历史工况数据为空:是
        # --------------------------------------------------------------------------------------------------------------
        else:  # else ->
            logger.error(f"[未处理的]热力站历史工况数据:为空")
            pass  # <- else
        pass  # for <-


pass  # day_heat_main <-


@CodeTimingUtil(name="累热模型数据处理[day_heat_main_data_process]")
def day_heat_main_data_process(station_id, station_data, model_name):
    #
    # 获取地区编码
    area_code = func_get_area_code(station_id)
    logger.info(f"地区编码: {area_code}")

    #
    # 补齐数据:天气数据
    station_data_add_temp: pd.DataFrame = Temperature_Missing_value_database(
        area_code=area_code,
        station_data=station_data
    )
    # 打印数据
    logger.info(f"补齐结果:\n {station_data_add_temp}")
    # 获取数据:室内温度
    dict_temperature: dict = func_read_inside_temperature_data(station_id=station_id)

    # TODO 打印KEY值的时间范围（最小，最大）
    # 打印数据
    # logger.info(f"室内温度:\n {dict_temperature}")
    logger.info(f"室内温度数据[dict_temperature][len]: {len(dict_temperature)}")
    # logger.info(f"室内温度数据[dict_temperature][key]: {dict_temperature.keys()}")

    # 重置索引
    station_data_add_temp.reset_index(drop=True, inplace=True)

    #
    shi_nei_wen_du = []
    shi_nei_wen_du_max = []
    shi_nei_wen_du_mix = []

    #
    time_matched_count_y = 0
    time_matched_count_n = 0

    # for ->
    for i, _ in enumerate(station_data_add_temp["collect_time"]):
        # 数据截取:截取时间字符串前13位,去掉分秒,保留到小时
        Time1 = str(_)[:13]
        # if ->
        if Time1 in dict_temperature:
            #
            # logger.info(f"时间已匹配到:{Time1}")
            time_matched_count_y += 1
            # 平均温度:加权平均值
            tem = func_calc_weighted_temper(dict_temperature[Time1])
            # 平均温度列表
            shi_nei_wen_du.append(tem)
            # 最大温度列表
            shi_nei_wen_du_max.append(max(dict_temperature[Time1]))
            # 最小温度列表
            shi_nei_wen_du_mix.append(min(dict_temperature[Time1]))
            pass  # if <-
        # else ->
        else:
            #
            # logger.warning(f"时间未匹配到:{Time1}")
            time_matched_count_n += 1
            # 删除数据:时间未匹配到的数据
            station_data_add_temp = station_data_add_temp.drop(index=[i])
            #
            pass  # else <-
        pass  # for <-

    #
    time_matched_count_y_and_n = time_matched_count_y + time_matched_count_n

    #
    # 打印数据:时间已匹配数量,时间未匹配数量
    logger.info(f"时间已匹配到[数量]: {time_matched_count_y}, {round(time_matched_count_y / time_matched_count_y_and_n, 2)}%")
    logger.info(f"时间未匹配到[数量]: {time_matched_count_n}, {round(time_matched_count_n / time_matched_count_y_and_n, 2)}%")

    # 重置索引
    station_data_add_temp.reset_index(drop=True, inplace=True)

    # 数据补齐:平均室温列,最大室温列,最小室温列
    station_data_add_temp["average_inside_temper"] = shi_nei_wen_du
    station_data_add_temp["max_inside_temper"] = shi_nei_wen_du_max
    station_data_add_temp["min_inside_temper"] = shi_nei_wen_du_mix

    # 打印数据
    logger.info(f"数据补齐:平均室温列,最大室温列,最小室温列:\n {station_data_add_temp}")
    logger.info(f"累热列数据：{station_data_add_temp['total_accum_heat']}")

    # if ->
    if station_data_add_temp is None or station_data_add_temp.empty:
        logger.info(f"数据库中没有可处理的数据")
        pass  # if <-
    else:  # else ->
        # 数据计算
        total_data = process_data_each_day_calculate(station_data_add_temp)
        logger.info(f"每日累热数据计算结果:\n {total_data}")
        logger.info(f"每日累热数据计算结果[index]:\n {total_data.index}")
        # logger.info(f"每日累热数据计算结果[index][to_numpy()]:\n {total_data.index.to_numpy()}") # 存在相同的KEY

        # 获取连接
        con = MySQLUtils.get_mysql_connection()

        # 获取游标
        cur = con.cursor()

        #
        total_data_len = len(total_data)

        # -> try:
        try:
            # for ->
            for i in range(total_data_len):
                # 读取数据:id
                id_ = DatabasePrimaryKeyGeneratorUtil.generate()
                # 插入语句
                sql = f"INSERT INTO `sn_control_model_hotstation_transition_day`" \
                      f"(" \
                      f"id,station_id,model_name,collect_time," \
                      f"min_outside_temper," \
                      f"max_outside_temper," \
                      f"average_outside_temper," \
                      f"min_inside_temper," \
                      f"max_inside_temper," \
                      f"average_inside_temper," \
                      f"day_heat" \
                      f") " \
                      f"VALUES (%d,%d,\'%s\'," \
                      f"str_to_date(\'%s\','%%Y-%%m-%%d %%H:%%i:%%s'), " \
                      f"%f,%f,%f,%f,%f,%f,%f)" \
                      % \
                      (id_,
                       station_id,
                       model_name,
                       total_data.iloc[i]["collect_time"],
                       total_data.iloc[i]["min_outside_temper"],
                       total_data.iloc[i]["max_outside_temper"],
                       total_data.iloc[i]["average_outside_temper"],
                       total_data.iloc[i]["min_inside_temper"],
                       total_data.iloc[i]["max_inside_temper"],
                       total_data.iloc[i]["average_inside_temper"],
                       total_data.iloc[i]["day_heat"])
                # 打印语句
                logger.info(f"插入语句[{i}/{total_data_len}]: {sql}")
                # 执行语句
                cur.execute(sql)
                # 提交事务:每10条提交一次
                # if ->
                if i % 10 == 0:
                    logger.warning(f"提交事务[i%10==0]:开始")
                    con.commit()
                    logger.warning(f"提交事务[i%10==0]:完成:[{i}/{total_data_len}][{round(i / total_data_len * 100, 2)}%]")
                    pass  # <- if
                pass  # for <-
            #
            # 更新语句:更新数据处理状态(status_accum=2, 0-未处理,1-处理中,2-已处理)
            sql2 = f"UPDATE sn_control_model_station SET status_accum=2 WHERE status_accum=1"
            logger.info(f"更新语句: {sql2}")
            # 执行语句
            cur.execute(sql2)
            # 提交事务
            con.commit()
            pass  # <- try:
        except BaseException as err:  # except ->
            # 打印异常
            logger.error(f"数据处理异常: {err}")
            # 回滚事务
            con.rollback()
            logger.warning(f"回滚事务[con.rollback()]")
            pass  # <- except
        finally:  # finally ->
            # 关闭游标
            cur.close()
            logger.info(f"关闭游标[cur.close()]")
            # 关闭链接
            con.close()
            logger.info(f"关闭连接[con.close()]")
            pass  # <- finally
        pass  # <- else


pass  # <- day_heat_main_data_process

if __name__ == '__main__':
    func_main_data_process_accum()
    pass
